/*
* Copyright (C) 2020 ~ 2024 chaigec All Rights Reserved.
*
* Author:     chaigec <chaigec@163.com>
* Maintainer: chaigec <chaigec@163.com>

 * Use of this source code is governed by MIT license that can be found in the
 * LICENSE file in the root of the source tree. All contributing project authors
 * may be found in the AUTHORS file in the root of the source tree.
*/

#include "MkRtmpParam.h"
#include "MkRtmpDemuxer.h"
#include "MkUtil/MkLog.h"

CMkRtmpParam::CMkRtmpParam()
    : m_PacketMaxLen(Len2K)
    , m_nPacketOffset(0)
    , m_RecvMaxLen(LenHalfM)
    , m_nRecvOffset(0)
    , m_InChunkSize(RtmpDefaultChunkSize)
    , m_OutChunkSize(RtmpDefaultChunkSize)
    , m_nServerBw(6000000)
    , m_nClientBw(6000000)
    , m_nClientBw2(0xFF)
    , m_TransactionId(2)
    , m_SendRecvSize(0)
{
    m_pPacketBuffer = (Uint8*)malloc(m_PacketMaxLen);
    m_pRecvBuffer = (Uint8*)malloc(m_RecvMaxLen);
}


Uint32 CMkRtmpParam::ParseRtmpMessage(const Uint8* pBuf, Uint32 nLen, Uint32& nUsed)
{
    MkRtmpHeader RtmpHeader;
    Uint8 *pBody = nullptr;
    Uint32 ErrorCode = CMkRtmpDemuxer::Parse(m_InChunkSize, pBuf, nLen, nUsed, &pBody, RtmpHeader);
    if (NoneError != ErrorCode) {
        nUsed = 0;
        return ErrorCode;
    }
    if (0 == RtmpHeader.BodySize) {
        MkWarningLog("recv body size 0 msg\n");
        return NoneError;
    }
    const Uint8 *pBodyEnd = pBody + RtmpHeader.BodySize;
    const Uint8 *pOffset = pBody;
    switch (RtmpHeader.CmdType) {
    case RtmpMsgChunkSize:
        pOffset = CMkAmf::DecodeUint32(pBody, pBodyEnd, m_InChunkSize);
        //MkDebugLog("set in chunk size:%d\n", m_InChunkSize);
        break;
    case RtmpMsgAbort:
        //to do 
        break;
    case RtmpMsgAcknowledgement:
        pOffset = CMkAmf::DecodeUint32(pBody, pBodyEnd, m_SendRecvSize);
        //MkDebugLog("set ack now size:%lu\n", m_SendRecvSize);
        break;
    case RtmpMsgControlEvent:
        ErrorCode = ParseRtmpControlEvent(pBody, pBodyEnd);
        //MkDebugLog("recv msg control event\n");
        break;
    case RtmpMsgWindownAcknowledgementSize:
        pOffset = CMkAmf::DecodeUint32(pBody, pBodyEnd, m_nServerBw);
        //MkDebugLog("recv set windown size:%d\n", m_nServerBw);
        break;
    case RtmpMsgSetPeerBandWith:
        //MkDebugLog("set peer band with\n");
        pOffset = CMkAmf::DecodeUint32(pBody, pBodyEnd, m_nClientBw);
        if (RtmpHeader.BodySize > 4) {
            pOffset = CMkAmf::DecodeUint8(pOffset, pBodyEnd, m_nClientBw2);
        } else {
            m_nClientBw2 = 0xFF;
        }
        break;
    case RtmpMsgAudio:
        ErrorCode = OnAudio(pBody, RtmpHeader.BodySize, RtmpHeader.TimeStamp);
        break;
    case RtmpMsgVideo:
        ErrorCode = OnVideo(pBody, RtmpHeader.BodySize, RtmpHeader.TimeStamp);
        break;
    case RtmpMsgDataAmf0:
    case RtmpMsgAmf0:
        ErrorCode = ParseRtmpAmf0Body(pBody, pBodyEnd);
        break;
    case RtmpMsgDataAmf3:
        break;
    case RtmpMsgShareAmf3:
        break;
    case RtmpMsgAmf3:
        ErrorCode = ParseRtmpAmf3Body(pBody, pBodyEnd);
        break;
    case RtmpMsgShareAmf0:
        break;

    case RtmpMsgAggregate:
        break;
    default:
        break;
    }
    MkCheckErrorPoint(pOffset, InvalidParams, "parse msg failed\n");
    return ErrorCode;
}

//Uint32 CMkRtmpParam::OnCommandRequest(const MkString& Command, Uint32 TransactionId, const MkVector<MkAmfObject>& VecObj)
//{
//    return NoneError;
//}

Uint32 CMkRtmpParam::OnCommandResponse(const MkString& Command, const MkVector<MkAmfObject>& VecObj, BOOL bSuccess)
{
    Uint32 ErrorCode = NoneError;
    if ("connect" == Command) {
        OnConnectResult(bSuccess);
    } else if ("createStream" == Command) {
        OnCreateStreamResult(bSuccess);
    }
    return ErrorCode;
}

Uint32 CMkRtmpParam::ParseRtmpControlEvent(const Uint8* pBegin, const Uint8* pEnd)
{
    Uint16 ControlType = 0;
    const Uint8* pOffset = CMkAmf::DecodeUint16(pBegin, pEnd, ControlType);
    MkCheckErrorPoint(pOffset, InvalidParams, "decode control type failed\n");
    Uint32 StreamId = 0;
    pOffset = CMkAmf::DecodeUint32(pOffset, pEnd, StreamId);
    MkCheckErrorPoint(pOffset, InvalidParams, "decode streamid failed\n");
    switch (ControlType) {
    case ControlEventStreamBegin:
        //OnStreamBegin(StreamId);
        break;
    case ControlEventStreamEof:
        if (RtmpPause1 == m_PauseState) {
            m_PauseState = RtmpPause2;
        }
        //OnStreamEof(StreamId);
        break;
    case ControlEventStreamDry:
        //OnStreamDry(StreamId);
        break;
    case ControlEventSetBufferLen:
    {
        Uint32 nLen = 0;
        pOffset = CMkAmf::DecodeUint32(pOffset, pEnd, nLen);
        MkCheckErrorPoint(pOffset, InvalidParams, "decode buffer len failed\n");
        //OnSetBufferLen(StreamId, nLen);
    }
    break;
    case ControlEventStreamIsRecored:
    {
        Uint32 TimeStamp = 0;
        pOffset = CMkAmf::DecodeUint32(pOffset, pEnd, TimeStamp);
        MkCheckErrorPoint(pOffset, InvalidParams, "decode timestamp failed\n");
        //OnStreamIdRecorded(StreamId);
    }
    break;
    case ControlEventPingRequest:
    {
        Uint32 TimeStamp = 0;
        pOffset = CMkAmf::DecodeUint32(pOffset, pEnd, TimeStamp);
        MkCheckErrorPoint(pOffset, InvalidParams, "decode timestamp failed\n");
        //OnStreamPingResponse(StreamId, TimeStamp);
    }
    break;
    case ControlEventPingResponse:
        break;
    case ControlEventBufferEmpty:
        break;
    case ControlEventBufferReady:
        break;
    default:
        break;
    }
    return NoneError;
}

Uint32 CMkRtmpParam::ParseRtmpAmf0Body(const Uint8* pBegin, const Uint8* pEnd)
{
    MkVector<MkAmfObject> VecObj;
    const Uint8* pOffset = CMkAmf::DecodeObject(pBegin, pEnd, VecObj, FALSE);
    if (!pOffset || VecObj.empty()) {
        return InvalidParams;
    }

    MkVector<MkAmfObject>::iterator it = VecObj.begin();
    if (MkAmfString != it->DataType) {
        return InvalidParams;
    }
    MkString CommandName = it->strValue;
    //MkDebugLog("recv amf0 cmd:%s\n", CommandName.c_str());
    VecObj.erase(it);
    Uint32 ErrorCode = NoneError;
    if ("_result" == CommandName) {
        ErrorCode = ParseResponse(VecObj, TRUE);
    } else if ("_error" == CommandName) {
        ErrorCode = ParseResponse(VecObj, FALSE);
    } else if ("onStatus" == CommandName) {
        ErrorCode = ParseResponse(VecObj, TRUE);
    } else {
        ErrorCode = OnCommandRequest(CommandName, VecObj);
    }
    return ErrorCode;
}

Uint32 CMkRtmpParam::ParseResponse(const MkVector<MkAmfObject>& VecObj, BOOL bSuccess)
{
    MkVector<MkAmfObject>::const_iterator it = VecObj.begin();
    if (MkAmfNumber != it->DataType) {
        return InvalidParams;
    }
    Uint32 ErrorCode = NoneError;
    Uint32 TransactionId = static_cast<Uint32>(it->NumberValue);
    MkString Cmd;
    if (1 == TransactionId) {
        Cmd = "connect";
    } else {
        MkMap<Uint32, MkString>::iterator itCmd = m_MapTransactionCmd.find(TransactionId);
        if (itCmd == m_MapTransactionCmd.end()) {
            return InvalidParams;
        }
        Cmd = itCmd->second;
        //m_MapTransactionCmd.erase(itCmd);
    }
    if ("publish" == Cmd) {
        it++;
        // command object
        if (it == VecObj.end()) {
            return InvalidParams;
        }
        it++;
        //info object
        if (it == VecObj.end() || MkAmfTypeObject != it->DataType) {
            return InvalidParams;
        }
        MkString Level;
        MkString Description;
        MkString Code;
        MkVector<MkAmfObject>::const_iterator itt = it->VecObjectValue.begin();
        for (; itt != it->VecObjectValue.end(); itt++) {
            if ("level" == itt->Name) {
                Level = itt->strValue;
            } else if ("description" == itt->Name) {
                Description = itt->strValue;
            } else if ("code" == itt->Name) {
                Code = itt->strValue;
            }
        }
        OnPublishResult(Level, Description, Code);
    } else {
        ErrorCode = OnCommandResponse(Cmd, VecObj, bSuccess);
    }
    return ErrorCode;
}

Uint32 CMkRtmpParam::ParseRtmpAmf3Body(const Uint8* pBegin, const Uint8* pEnd)
{
    MkVector<MkAmfObject> VecObj;
    const Uint8* pOffset = CMkAmf::DecodeAmf3Object(pBegin, pEnd, VecObj, FALSE);
    MkCheckErrorPoint(pOffset, InvalidParams, "decode amf3 failed\n");
    MkVector<MkAmfObject>::iterator it = VecObj.begin();
    for (; it != VecObj.end(); it++) {
        if ("onBWDone" == it->Name) {

        }
    }
    return NoneError;
}

Uint32 CMkRtmpParam::AddMapTransaction(Uint32& Id, const MkString& Cmd)
{
    if (1 == Id) {
        m_MapTransactionCmd.clear();
    }
    m_MapTransactionCmd[Id++] = Cmd;
    return NoneError;
}

Uint32 CMkRtmpParam::OnCommandRequest(const MkString& Command, const MkVector<MkAmfObject>& VecObj)
{
    return NoneError;
}

Uint32 CMkRtmpParam::OnAudio(const Uint8* pBuf, Uint32 nLen, Uint32 TimeStamp)
{
    return NoneError;
}

Uint32 CMkRtmpParam::OnVideo(const Uint8* pBuf, Uint32 nLen, Uint32 TimeStamp)
{
    return NoneError;
}

Uint32 CMkRtmpParam::OnMetaData(const MkVector<MkAmfObject>& VecObj)
{
    return NoneError;
}

Uint32 CMkRtmpParam::OnConnectResult(BOOL bSuccess)
{
    return NoneError;
}

Uint32 CMkRtmpParam::OnCreateStreamResult(BOOL bSuccess)
{
    return NoneError;
}

Uint32 CMkRtmpParam::OnPublishResult(const MkString Level, const MkString& Description, const MkString& Code)
{
    return NoneError;
}

CMkRtmpParam::~CMkRtmpParam()
{
    m_MapTransactionCmd.clear();
    MkFree(m_pRecvBuffer);
    MkFree(m_pPacketBuffer);
}